/*+**************************************************************************/
/***                                                                      ***/
/***   This file is distributed under a BSD license.                      ***/
/***   See LICENSE.txt for details.                                       ***/
/***                                                                      ***/
/**************************************************************************+*/

/****************************************************************************/
/***                                                                      ***/
/***   (C) 2005 Dierk Ohlerich, all rights reserved                       ***/
/***                                                                      ***/
/****************************************************************************/

asc
{
  cbuffer sSimpleMaterialPara : register(c0) : slot vs 0
  {
    row_major float4x4 mvp;     // rotation for light vector (not really needed)
    float4x3 mv;
    float4x3 m;

    // current asc "float" single float members doesn't work:    
    //  proj.i.x, proj.j.y, proj.k.z, proj.k.w
    //  proj.l.z, proj.l.w, proj.k.x, proj.k.y;
    float4 proj0;
    float4 proj1;

    extern void Set(const sViewport &view)
    {
      mvp = view.ModelScreen;
      mv = view.ModelView;
      m = view.Model;

      const sMatrix44 &proj = view.PMatrix();
      proj0.x = proj.i.x; proj0.y = proj.j.y; proj0.z = proj.k.z; proj0.w = proj.l.x;
      proj1.x = proj.l.z; proj1.y = proj.l.y; proj1.z = proj.k.x; proj1.w = proj.k.y;
    }
  };

  cbuffer sSimpleMaterialEnvPara : register(c0) : slot vs 0
  {
    row_major float4x4 mvp;     // rotation for light vector (not really needed)
    float4x3 mv;
    float4x3 m;

    // current asc "float" single float members doesn't work:    
    //  proj.i.x, proj.j.y, proj.k.z, proj.k.w
    //  proj.l.z, proj.l.w, proj.k.x, proj.k.y;
    float4 proj0;
    float4 proj1;

    float4 ld[3];               // light direction
    float4 la;                  // ambient
    float4 lc[4];               // light color


    extern void Set(const sViewport &view,const sMaterialEnv &env)
    {
      sMatrix34 m;
      sVector30 l[4];

      mvp = view.ModelScreen;
      mv = view.ModelView;
      m = view.Model;

      const sMatrix44 &proj = view.PMatrix();
      proj0.x = proj.i.x; proj0.y = proj.j.y; proj0.z = proj.k.z; proj0.w = proj.l.x;
      proj1.x = proj.l.z; proj1.y = proj.l.y; proj1.z = proj.k.x; proj1.w = proj.k.y;

      m = view.Model;
      m.Trans3();

      l[0] = env.LightDir[0]*m;
      l[1] = env.LightDir[1]*m;
      l[2] = env.LightDir[2]*m;
      l[3] = env.LightDir[3]*m;

      ld[0].Init(-l[0].x,-l[1].x,-l[2].x,-l[3].x);
      ld[1].Init(-l[0].y,-l[1].y,-l[2].y,-l[3].y);
      ld[2].Init(-l[0].z,-l[1].z,-l[2].z,-l[3].z);
      la   .InitColor(env.AmbientColor);
      lc[0].InitColor(env.LightColor[0]);
      lc[1].InitColor(env.LightColor[1]);
      lc[2].InitColor(env.LightColor[2]);
      lc[3].InitColor(env.LightColor[3]);
    }
  };

  permute sSimpleMaterialVSPerm
  {
    Color;
    UV0;
    UV1;
    Light;
    assert(UV1 implies UV0);    
  };

  permute sSimpleMaterialPSPerm
  {
    T0 { T0Off,T0Mul };
    T1 { T1Off,T1Mul,T1Add };
    assert(T1 implies T0);
  };

  permute sYUVMaterialVSPerm
  {
    Color;
  };
  
  permute sYUVMaterialPSPerm
  {
    AlphaTex;
  };
  
}

/****************************************************************************/

material sSimpleMaterial
{
  header
  {
    sBool AddTex1;
  }
  
  new
  {
    AddTex1 = 0;
  }

  prepare
  {
    sInt n;
    
    // pick vertex shader

    n = 0;
    if(format->GetAvailMask() & (1<<sVF_COLOR0)) 
      n |= sSimpleMaterialVSPermMask_Color;
    if(format->GetAvailMask() & (1<<sVF_UV0))    
      n |= sSimpleMaterialVSPermMask_UV0;
    if(format->GetAvailMask() & (1<<sVF_UV1))    
      n |= sSimpleMaterialVSPermMask_UV1;
    if((format->GetAvailMask() & (1<<sVF_NORMAL)) && (Flags & sMTRL_LIGHTING) ) 
      n |= sSimpleMaterialVSPermMask_Light;
    VertexShader = VS(n);

    // pick pixel shader (number of textures)

    n = 0;
    if(Texture[0] || (TFlags[0]&sMTF_EXTERN))
      n |= sSimpleMaterialPSPerm_T0Mul;
    if(Texture[1] || (TFlags[1]&sMTF_EXTERN))
    {
      if(AddTex1)
        n |= sSimpleMaterialPSPerm_T1Add;
      else
        n |= sSimpleMaterialPSPerm_T1Mul;
    }
    PixelShader = PS(n); 
  }
  
  vs
  {
    asc vs_2_0                 // hlsl code
    {
      use sSimpleMaterialEnvPara;
      use sSimpleMaterialVSPerm;
      void main
      (
        in float3 in_pos : POSITION,
        in float3 in_norm : NORMAL : pif(Light),
        in float4 in_col : COLOR0 : pif(Color),
        in float2 in_uv0 : TEXCOORD0 : pif(UV0),
        in float2 in_uv1 : TEXCOORD1 : pif(UV1),
        out float4 out_col : COLOR0,
        out float2 out_uv0 : TEXCOORD0 : pif(UV0),
        out float2 out_uv1 : TEXCOORD1 : pif(UV1),
        out float4 out_pos : POSITION, 
      )
      {
        float4 c;
        pif(Light)
        {
          float3 norm = normalize(in_norm);
          float4 i = ld[0]*norm.x + ld[1]*norm.y + ld[2]*norm.z;
          i = max(i,0);
          c = la + lc[0]*i.x + lc[1]*i.y + lc[2]*i.z + lc[3]*i.w;
        }
        pelse
        {
          c = 1;
        }
        pif(UV0) out_uv0 = in_uv0;
        pif(UV1) out_uv1 = in_uv1;
        pif(Color) c *= in_col;

        out_col = c;
        out_pos = mul(float4(in_pos,1),mvp);
      }
    }
  }

  ps
  {
    asc ps_2_0 
    {
      use sSimpleMaterialPSPerm;

      sampler2D s0 : register(s0) : pif(T0);
      sampler2D s1 : register(s1) : pif(T1);

      void main
      (
        in float4 color : COLOR0,
        in float2 uv0 : TEXCOORD0 : pif(T0),
        in float2 uv1 : TEXCOORD1 : pif(T1),
        out float4 result : COLOR0
      )
      {
        result = color;
        pif(T0==T0Mul) result *= tex2D(s0,uv0);
        pif(T1==T1Add) result += tex2D(s1,uv1);
        pif(T1==T1Mul) result *= tex2D(s1,uv1);
      }
    }
    
  }
};

/****************************************************************************/
/***                                                                      ***/
/***   sCubeMaterial                                                      ***/
/***                                                                      ***/
/****************************************************************************/

material sCubeMaterial
{
  vs
  {
    asc vs_2_0                 // hlsl code
    {
      use sSimpleMaterialPara;
      void main
      (
        in float4 in_pos : POSITION,
        in float3 in_norm : NORMAL,
        out float4 out_pos : POSITION,
        out float3 out_norm : TEXCOORD0,
      )
      {
        out_norm = in_norm;
        out_pos = mul(in_pos,mvp);
      }
    }
  }

  ps
  {
    asc ps_2_0
    {
      samplerCUBE s0 : register(s0);

      void main
      (
        in float3 normal : TEXCOORD0,
        out float4 result : COLOR0
      )
      {
        result = texCUBE(s0,normal);
      }
    }
    
  }
};

/****************************************************************************/
/***                                                                      ***/
/***   sYUVMaterial                                                       ***/
/***                                                                      ***/
/****************************************************************************/

material sYUVMaterial
{
  header
  {
    void Set(sCBufferBase *cb) { sMaterial::Set(cb); }
  }
  
  prepare
  {      
    sInt n=0;
    if(format->GetAvailMask() & (1<<sVF_COLOR0)) 
      n |= sYUVMaterialVSPermMask_Color;
    VertexShader = VS(n);
           
    n=0;
    if (Texture[3])
      n |= sYUVMaterialPSPermMask_AlphaTex;    
    PixelShader = PS(n); 
  }
  
  vs
  {
    asc vs_2_0                 // hlsl code
    {
      use sSimpleMaterialPara;
      use sYUVMaterialVSPerm;
      void main
      (
        in float3 in_pos : POSITION,
        in float4 in_col : COLOR0 : pif(Color),
        in float2 in_uv : TEXCOORD0,
        out float2 out_uv : TEXCOORD0,
        out float4 out_color : COLOR0,
        out float4 out_pos : POSITION,         
      )
      {
        out_uv = in_uv;
        out_pos = mul(float4(in_pos,1),mvp);
        pif (Color)
          out_color = in_col;
        pelse
          out_color = float4(1,1,1,1);
      }
    }
  }

  ps
  {
    asc ps_2_0
    {
      use sYUVMaterialPSPerm;

      sampler2D s0 : register(s0);    // y component
      sampler2D s1 : register(s1);    // u component
      sampler2D s2 : register(s2);    // v component
      sampler2D s3 : register(s3) : pif(AlphaTex);    // alpha texture

      void main
      (
        in float2 uv0 : TEXCOORD0,
        in float4 col : COLOR0,
        out float4 result : COLOR0
      )
      {
        float c = (tex2D(s0,uv0).x - (1.f / 16)) * (298.f / 255.f); // y component
        float d = tex2D(s1,uv0).x - 0.5f;       // u component
        float e = tex2D(s2,uv0).x - 0.5f;       // v component

        result.r = saturate(c + (409.f / 255.f) * e);
        result.g = saturate(c - (100.f / 255.f) * d - (208.f / 255.f) * e);
        result.b = saturate(c + (516.f / 255.f) * d);
        result.a = 1.f;
        result*=col;
        
        pif (AlphaTex) result.a*=tex2D(s3,uv0).a;
      }
    }
  }
};

/****************************************************************************/

// add TC3 material definitions if applicable
include_asc mayfail "../../../tc3/main/consoles/shaders2.asc";
